namespace Microsoft.ServiceModel.Samples.Discovery
{
    using System;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Collections.Generic;
    using System.ServiceModel.Description;
    using Microsoft.ServiceModel.Samples.Discovery.Protocol;

    public class MatchCriteria
    {
        public static readonly Uri ScopeMatchByPrefix =
            new Uri(ProtocolStrings.ScopeMatchByPrefix);

        public static readonly Uri ScopeMatchByExact =
            new Uri(ProtocolStrings.ScopeMatchByExact);

        public static readonly Uri ScopeMatchByUuid =
            new Uri(ProtocolStrings.ScopeMatchByUuid);

        public static readonly Uri ScopeMatchByLdap =
            new Uri(ProtocolStrings.ScopeMatchByLdap);

        ContactTypeCollection typesField;
        ScopeCollection scopesField;
        XmlElement[] anyField;
        XmlAttribute[] anyAttrField;

        public MatchCriteria()
        {
            Initialize(null, null);
        }
        
        public MatchCriteria(Type type)
            : this(GetDiscoveryType(type))
        {
        }

        public MatchCriteria(Type type, Uri scope, Uri scopeMatchBy)
            : this(GetDiscoveryType(type), scope, scopeMatchBy)
        {
        }

        public MatchCriteria(XmlQualifiedName type)
        {
            if (type == null)
                throw new ArgumentNullException("type");

            ContactTypeCollection types = new ContactTypeCollection();
            types.Add(type);
            Initialize(types, null);
        }

        public MatchCriteria(XmlQualifiedName type, Uri scope, Uri scopeMatchBy)
        {
            if (type == null)
                throw new ArgumentNullException("type");

            if (scope == null)
                throw new ArgumentNullException("scope");

            if (scopeMatchBy == null)
                throw new ArgumentNullException("scopeMatchBy");

            ContactTypeCollection types = new ContactTypeCollection();
            types.Add(type);

            ScopeCollection scopes = new ScopeCollection();
            scopes.Add(scope);
            scopes.MatchBy = scopeMatchBy;
            Initialize(types, scopes);
        }

        public MatchCriteria(ContactTypeCollection types, ScopeCollection scopes)
        {
            Initialize(types, scopes);
        }

        void Initialize(ContactTypeCollection types, ScopeCollection scopes)
        {
            this.typesField = types;
            this.scopesField = scopes;
            this.anyAttrField = null;
            this.anyField = null;
        }

        [XmlElement]
        public ContactTypeCollection Types
        {
            get
            {
                return this.typesField;
            }

            set
            {
                this.typesField = value;
            }
        }

        [XmlElement]
        public ScopeCollection Scopes
        {
            get
            {
                return this.scopesField;
            }

            set
            {
                this.scopesField = value;
            }
        }

        [XmlIgnore]
        public Uri ScopeMatchBy
        {
            get
            {
                if (this.scopesField != null)
                {
                    return this.scopesField.MatchBy;
                }
                else
                {
                    return ScopeMatchByPrefix;
                }
            }

            set
            {
                if (value == null)
                    throw new ArgumentNullException("value");

                if (this.scopesField == null)
                    this.scopesField = new ScopeCollection();
                
                this.scopesField.MatchBy = value;
            }
        }

        [XmlAnyElement]
        public XmlElement[] AnyElements
        {
            get
            {
                return this.anyField;
            }
            set
            {
                this.anyField = value;
            }
        }

        /// <remarks/>
        [XmlAnyAttributeAttribute()]
        public XmlAttribute[] AnyAttributes
        {
            get
            {
                return this.anyAttrField;
            }
            set
            {
                this.anyAttrField = value;
            }
        }


        public static XmlQualifiedName GetDiscoveryType(Type contractType)
        {
            if (contractType == null)
                throw new ArgumentNullException("contractType");

            ContractDescription contract = ContractDescription.GetContract(contractType);
            return new XmlQualifiedName(contract.Name, contract.Namespace);
        }
    }
}
